<?php

/**
 * Inflector helper class.
 *
 * Pluralize and singularize English words.
 *
 * @version  $Id: inflector.php 2 2009-10-02 23:06:43Z perfilev $
 * @package  System
 */

class Inflector
{
	/**
	 * @var  array  Cached inflections.
	 */
	protected static $cache = array();

	/**
	 * @var a rray  Uncountable words.
	 */
	protected static $uncountable = array(
		'access',
		'advice',
		'art',
		'baggage',
		'dances',
		'equipment',
		'fish',
		'fuel',
		'furniture',
		'food',
		'heat',
		'honey',
		'homework',
		'impatience',
		'information',
		'knowledge',
		'luggage',
		'money',
		'music',
		'news',
		'patience',
		'progress',
		'pollution',
		'research',
		'rice',
		'sand',
		'series',
		'sheep',
		'sms',
		'species',
		'staff',
		'toothpaste',
		'traffic',
		'understanding',
		'water',
		'weather',
		'work',
	);
	
	/**
	 * @var  arrayy  Irregular words.
	 */
	protected static $irregular = array(
		'child' => 'children',
		'clothes' => 'clothing',
		'man' => 'men',
		'movie' => 'movies',
		'person' => 'people',
		'woman' => 'women',
		'mouse' => 'mice',
		'goose' => 'geese',
		'ox' => 'oxen',
		'leaf' => 'leaves',
		'course' => 'courses',
		'size' => 'sizes',
	);

	/**
	 * Checks if a word is defined as uncountable.
	 *
	 * @param   string  $word  Word to check.
	 * @return  boolean
	 */
	public static function uncountable($word)
	{
		return in_array(strtolower($word), self::$uncountable);
	}

	/**
	 * Makes a plural word singular.
	 *
	 * @param  string   $word   Word to singularize.
	 * @param  integer  $count  Number of things.
	 * @return string
	 */
	public static function singular($word, $count = null)
	{
		$word = strtolower($word);
		
		if (is_string($count)) {
			$count = (int) $count;
		}
		if ($count === 0 || $count > 1) {
			return $word;
		}
		
		$key = 's' . $word . $count;
		
		if (array_key_exists($key, self::$cache)) {
			return self::$cache[$key];
		}

		if (in_array($word, self::$uncountable)) {
			return self::$cache[$key] = $word;
		}

		if ($irregular = array_search($word, self::$irregular)) {
			$word = $irregular;
		} elseif (preg_match('/[sxz]es$/', $word) || preg_match('/[^aeioudgkprt]hes$/', $word)) {
			$word = substr($word, 0, -2);
		} elseif (preg_match('/[^aeiou]ies$/', $word)) {
			$word = substr($word, 0, -3) . 'y';
		} elseif (substr($word, -1) === 's' && substr($word, -2) !== 'ss') {
			$word = substr($word, 0, -1);
		}

		return self::$cache[$key] = $word;
	}

	/**
	 * Makes a singular word plural.
	 *
	 * @param  string   $word   Word to pluralize.
	 * @param  integer  $count  Number of things.
	 * @return string
	 */
	public static function plural($word, $count = null)
	{
		$word = strtolower($word);

		if (is_string($count)) {
			$count = (int) $count;
		}
		if ($count === 1) {
			return $word;
		}

		$key = 'p' . $word . $count;

		if (array_key_exists($key, self::$cache)) {
			return self::$cache[$key];
		}

		if (in_array($word, self::$uncountable)) {
			return self::$cache[$key] = $word;
		}

		if (array_key_exists($word, self::$irregular)) {
			$word = self::$irregular[$word];
		} elseif (preg_match('/[sxz]$/', $word) && preg_match('/[^aeioudgkprt]h$/', $word)) {
			$word .= 'es';
		} elseif (preg_match('/[^aeiou]y$/', $word)) {
			$word = substr_replace($word, 'ies', -1);
		} else {
			$word .= 's';
		}

		return self::$cache[$key] = $word;
	}
}
